//-------------------------------------------------------------------
//	Copyright (c) 2010-2012 Zhirnov Andrey
//	This file is part of the "UXGEN" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#ifndef _UX_SCENE_MESSAGES_H
#define _UX_SCENE_MESSAGES_H

#include "SceneBase.h"
#include "../../Systems/AllSystems.h"

namespace Engine
{
namespace Scene
{

	struct TSNCompMessage;
	struct TSNodeMessage;
	struct TSceneMessage;
	struct TSSystemMessage;

	typedef IScene< TSNodeMessage, TSNCompMessage, TSSystemMessage, TSceneMessage >		IBaseScene;
	typedef IBaseScene::ISceneNodeComponent												IBaseSNComponent;
	typedef IBaseScene::ISceneNode														IBaseSceneNode;
	typedef IBaseScene::ISceneSystem													IBaseSceneSystem;


	template <typename T, typename F>
	inline bool SendMsgForEach(const T &sArray, F &sMsg, typename T::element_t &tResult)
	{
		for (usize i = 0; i < sArray.Count(); ++i) {
			if ( sMsg( sArray[i] ) )
			{
				tResult = sArray[i];
				return true;
			}
		}
		return false;
	}

	
//-------------------------------------------------------------------


	//
	// Component Messages
	//
	
	struct TSNCompMessage
	{
		// types
		struct TUpdate
		{
			IBaseSceneNode *	pNode;
			float				fTimeDelta;
		};

		enum EMsgType
		{
			UPDATE		= 0,	// TUpdate

			// flags //
			FLAG_SET	= 0x00010000,
			FLAG_GET	= 0x00020000,


			_MSG_MASK	= 0x0000FFFF,
			_FLAGS_MASK	= 0xFFFF0000,

			UNKNOWN		= _MSG_MASK
		};

		union UMessageData
		{
			TUpdate		sUpd;
		};


		// values
		UMessageData	sData;
		EMsgType		eType;


		// methods
		TSNCompMessage(): eType(UNKNOWN)	{ memset( &sData, 0, sizeof(sData) ); }


		bool operator () (IBaseSNComponent *pObj)
		{
			return pObj->ProcessMessage( *this );
		}


		void Update(IBaseSceneNode *pNode, float fTime)
		{
			eType					= UPDATE;
			sData.sUpd.pNode		= pNode;
			sData.sUpd.fTimeDelta	= fTime;
		}
	};


//-------------------------------------------------------------------


	//
	// Scene Node Messages
	//

	struct TSNodeMessage
	{
		// types
		struct TGetNode
		{
			const string	*	pName;
			IBaseSceneNode	*	pResult;
		};

		enum EMsgType
		{
			UPDATE		= 0,

			NODE,		// TGetNode

			// flags //
			FLAG_SET	= 0x00010000,
			FLAG_GET	= 0x00020000,


			_MSG_MASK	= 0x0000FFFF,
			_FLAGS_MASK	= 0xFFFF0000,

			UNKNOWN		= _MSG_MASK
		};

		union UMessageData
		{
			TGetNode	sGetNode;
		};


		// values
		UMessageData	sData;
		EMsgType		eType;


		// methods
		TSNodeMessage() : eType(UNKNOWN)	{ memset( &sData, 0, sizeof(sData) ); }
		

		bool operator () (IBaseSceneNode *pObj)
		{
			return pObj->ProcessMessage( *this );
		}


		void GetNode(const string &sName)
		{
			eType					= EMsgType( FLAG_GET | NODE );
			sData.sGetNode.pName	= &sName;
			sData.sGetNode.pResult	= nullptr;
		}
	};
	

//-------------------------------------------------------------------


	//
	// Scene System Message
	//
	
	struct TSSystemMessage
	{
		// types
		struct TGetSystem
		{
			const string	 *	pName;
			IBaseSceneSystem *	pResult;
		};


		enum EMsgType
		{
			UPDATE		= 0,

			SYSTEM,		// TGetSystem

			// flags //
			FLAG_SET	= 0x00010000,
			FLAG_GET	= 0x00020000,


			_MSG_MASK	= 0x0000FFFF,
			_FLAGS_MASK	= 0xFFFF0000,

			UNKNOWN		= _MSG_MASK
		};

		union UMessageData
		{
			// get //
			TGetSystem		sGetSys;
		};


		// values
		UMessageData		sData;
		EMsgType			eType;


		// methods
		TSSystemMessage(): eType(UNKNOWN)	{ memset( &sData, 0, sizeof(sData) ); }
		

		bool operator () (IBaseSceneSystem *pObj)
		{
			return pObj->ProcessMessage( *this );
		}


		void GetSystem(const string &sName)
		{
			eType					= EMsgType( FLAG_GET | SYSTEM );
			sData.sGetSys.pName		= & sName;
			sData.sGetSys.pResult	= nullptr;
		}
	};


//-------------------------------------------------------------------


	//
	// Scene Messages
	//

	struct TSceneMessage
	{
		// types

		// values


		// methods
		bool operator () (IBaseScene *pObj)
		{
			return pObj->ProcessMessage( *this );
		}
	};


//-------------------------------------------------------------------

}	// Scene
}	// Engine

#endif	// _UX_SCENE_MESSAGES_H